# coding:utf-8
from qfluentwidgets import (SwitchSettingCard, FolderListSettingCard,
                            OptionsSettingCard, PushSettingCard,
                            HyperlinkCard, PrimaryPushSettingCard, ScrollArea,
                            ComboBoxSettingCard, ExpandLayout, Theme, CustomColorSettingCard,
                            setTheme, setThemeColor, isDarkTheme, setFont)
from qfluentwidgets import FluentIcon as FIF
from qfluentwidgets import SettingCardGroup as CardGroup
from qfluentwidgets import InfoBar, Dialog
from PySide6.QtCore import Qt, Signal, QUrl, QStandardPaths, QTimer, QProcess
from PySide6.QtGui import QDesktopServices, QFont
from PySide6.QtWidgets import QWidget, QLabel, QFileDialog, QApplication
from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
import json
import os
import requests # Added for new API calls

from ..common.config import cfg, isWin11
from ..common.setting import AUTHOR, VERSION, YEAR, APP_NAME,LLM_URL
from ..common.signal_bus import signalBus
from ..common.style_sheet import StyleSheet
from ..common.setting import API_URL
from ..components.dropdown_card import DropDownSettingCard
from ..components.line_edit_card import LineEditSettingCard

class SettingCardGroup(CardGroup):

   def __init__(self, title: str, parent=None):
       super().__init__(title, parent)
       setFont(self.titleLabel, 14, QFont.Weight.DemiBold)



class SettingInterface(ScrollArea):
    """ Setting interface """

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.scrollWidget = QWidget()
        self.expandLayout = ExpandLayout(self.scrollWidget)

        # setting label
        self.settingLabel = QLabel(self.tr("Settings"), self)

        # LLM settings
        self.llmGroup = SettingCardGroup(
            self.tr('大模型'), self.scrollWidget
        )
        self.customLlmNameCard = LineEditSettingCard(
            FIF.EDIT,
            self.tr('大模型名称'),
            self.tr('输入您的大模型名称'),
            cfg.customLlmName,
            parent=self.llmGroup
        )
        self.llmApiKeyCard = LineEditSettingCard(
            FIF.CERTIFICATE,
            self.tr('大模型密钥'),
            self.tr('输入您的大模型 API 密钥'),
            cfg.llmApiKey,
            parent=self.llmGroup
        )
        # Add a save button for LLM settings
        self.saveLlmSettingsCard = PrimaryPushSettingCard(
            self.tr('保存大模型配置'),
            FIF.SAVE,
            self.tr('保存大模型配置'),
            self.tr('将大模型名称和API密钥保存至服务器'),
            parent=self.llmGroup
        )
        # Add a link to LLM proxy platform
        self.llmProxyCard = HyperlinkCard(
            LLM_URL,
            self.tr('大模型中转平台'),
            FIF.LINK,
            self.tr('打开大模型中转平台'),
            self.tr('访问智拓AI大模型中转平台'),
            self.llmGroup
        )

        # personalization
        self.personalGroup = SettingCardGroup(
            self.tr('Personalization'), self.scrollWidget)
        self.micaCard = SwitchSettingCard(
            FIF.TRANSPARENT,
            self.tr('Mica effect'),
            self.tr('Apply semi transparent to windows and surfaces'),
            cfg.micaEnabled,
            self.personalGroup
        )
        self.themeCard = ComboBoxSettingCard(
            cfg.themeMode,
            FIF.BRUSH,
            self.tr('Application theme'),
            self.tr("Change the appearance of your application"),
            texts=[
                self.tr('Light'), self.tr('Dark'),
                self.tr('Use system setting')
            ],
            parent=self.personalGroup
        )
        self.themeColorCard = CustomColorSettingCard(
            cfg.themeColor,
            FIF.PALETTE,
            self.tr('主题颜色'),
            self.tr('更改应用主题颜色'),
            self.personalGroup
        )
        self.zoomCard = ComboBoxSettingCard(
            cfg.dpiScale,
            FIF.ZOOM,
            self.tr("Interface zoom"),
            self.tr("Change the size of widgets and fonts"),
            texts=[
                "100%", "125%", "150%", "175%", "200%",
                self.tr("Use system setting")
            ],
            parent=self.personalGroup
        )
        self.languageCard = ComboBoxSettingCard(
            cfg.language,
            FIF.LANGUAGE,
            self.tr('Language'),
            self.tr('Set your preferred language for UI'),
            texts=['简体中文', '繁體中文', 'English', self.tr('Use system setting')],
            parent=self.personalGroup
        )

        # update software
        self.updateSoftwareGroup = SettingCardGroup(
            self.tr("Software update"), self.scrollWidget)
        self.updateOnStartUpCard = SwitchSettingCard(
            FIF.UPDATE,
            self.tr('Check for updates when the application starts'),
            self.tr('The new version will be more stable and have more features'),
            configItem=cfg.checkUpdateAtStartUp,
            parent=self.updateSoftwareGroup
        )

        # application
        self.aboutGroup = SettingCardGroup(self.tr('About'), self.scrollWidget)
        
        self.aboutCard = PrimaryPushSettingCard(
            self.tr('Check update'),
            ":/qfluentwidgets/images/logo.png",
            self.tr('About') + " " + APP_NAME,
            '© ' + self.tr('Copyright') + f" {YEAR}, {AUTHOR}. " +
            self.tr('Version') + " " + VERSION,
            self.aboutGroup
        )
        self.openSourceCard = HyperlinkCard(
            'https://gitee.com/zywxxz/ztough-client.git',
            self.tr('Gitee 仓库'),
            FIF.GITHUB,
            self.tr('客户端开源'),
            self.tr('智拓AI严格遵循qfluentwidgets框架GPL-3.0开源协议'),
            self.aboutGroup
        )

        self.__initWidget()
        self.network_manager = QNetworkAccessManager(self)
        # 应用启动时自动检查更新 (延迟执行，避免阻塞UI)
        QTimer.singleShot(1500, self.check_for_updates_on_startup)

    def __initWidget(self):
        self.resize(1000, 800)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setViewportMargins(0, 100, 0, 20)
        self.setWidget(self.scrollWidget)
        self.setWidgetResizable(True)
        self.setObjectName('settingInterface')

        # initialize style sheet
        setFont(self.settingLabel, 23, QFont.Weight.DemiBold)
        self.scrollWidget.setObjectName('scrollWidget')
        self.settingLabel.setObjectName('settingLabel')
        StyleSheet.SETTING_INTERFACE.apply(self)
        self.scrollWidget.setStyleSheet("QWidget{background:transparent}")

        self.micaCard.setEnabled(isWin11())

        # initialize layout
        self.__initLayout()
        self._connectSignalToSlot()

    def __initLayout(self):
        self.settingLabel.move(36, 50)

        self.llmGroup.addSettingCard(self.customLlmNameCard)
        self.llmGroup.addSettingCard(self.llmApiKeyCard)
        self.llmGroup.addSettingCard(self.saveLlmSettingsCard)
        self.llmGroup.addSettingCard(self.llmProxyCard)

        self.personalGroup.addSettingCard(self.micaCard)
        self.personalGroup.addSettingCard(self.themeCard)
        self.personalGroup.addSettingCard(self.themeColorCard)
        self.personalGroup.addSettingCard(self.zoomCard)
        self.personalGroup.addSettingCard(self.languageCard)

        self.updateSoftwareGroup.addSettingCard(self.updateOnStartUpCard)

        self.aboutGroup.addSettingCard(self.aboutCard)
        self.aboutGroup.addSettingCard(self.openSourceCard)

        # add setting card group to layout
        self.expandLayout.setSpacing(28)
        self.expandLayout.setContentsMargins(36, 10, 36, 0)
        self.expandLayout.addWidget(self.llmGroup)
        self.expandLayout.addWidget(self.personalGroup)
        self.expandLayout.addWidget(self.updateSoftwareGroup)
        self.expandLayout.addWidget(self.aboutGroup)

    def _showRestartTooltip(self):
        """ show restart tooltip """
        InfoBar.success(
            self.tr('Updated successfully'),
            self.tr('Configuration takes effect after restart'),
            duration=1500,
            parent=self
        )

    def _connectSignalToSlot(self):
        """ connect signal to slot """
        cfg.appRestartSig.connect(self._showRestartTooltip)

        # personalization
        cfg.themeChanged.connect(setTheme)
        self.themeColorCard.colorChanged.connect(lambda c: setThemeColor(c))
        self.micaCard.checkedChanged.connect(signalBus.micaEnableChanged)

        # check update
        self.aboutCard.clicked.connect(self.check_for_updates_interactive)

        # LLM settings persistence - connect save button instead of text editing
        self.saveLlmSettingsCard.clicked.connect(self._on_custom_llm_settings_changed)
        # Remove the automatic connections
        # self.customLlmNameCard.lineEdit.textEdited.connect(self._on_custom_llm_settings_changed)
        # self.llmApiKeyCard.lineEdit.textEdited.connect(self._on_custom_llm_settings_changed)

    def _on_custom_llm_settings_changed(self):
        """ Handles custom LLM settings change and saves to server """
        custom_name = cfg.get(cfg.customLlmName)
        api_key = cfg.get(cfg.llmApiKey)

        # Only proceed if all custom LLM fields are filled, or if user intends to clear them
        # For simplicity, we'll save even if some fields are empty, API/DB should handle constraints if any.
        # User might want to clear settings.

        token = cfg.get(cfg.jwtToken)
        if not token:
            InfoBar.warning(self.tr("登录失效"), self.tr("请先登录后再修改自定义大模型设置。"), parent=self)
            return

        custom_settings = {
            "key": api_key,
            "model": custom_name
        }
        # The API for /user/model-config expects the value for "model_config" to be a JSON *string*.
        custom_settings_json_string = json.dumps(custom_settings)

        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
        data = {"model_config": custom_settings_json_string} # Key is "model_config"

        try:
            # Using requests library as requested by user
            response = requests.post(f"{API_URL}/user/model-config", headers=headers, json=data, timeout=5)
            if response.status_code == 200:
                response_data = response.json()
                if response_data.get("status") == "success":
                    InfoBar.success(self.tr("设置成功"), self.tr("自定义大模型设置已保存。"), parent=self)
                else:
                    InfoBar.error(self.tr("设置失败"), response_data.get("message", self.tr("未能保存自定义大模型设置。")), parent=self)
            else:
                InfoBar.warning(self.tr("设置失败"),"大模型配置无变化", parent=self)
        except requests.exceptions.RequestException as e:
            InfoBar.error(self.tr("网络错误"), self.tr("保存自定义大模型设置失败，请检查网络连接或稍后重试。"), parent=self)
        except Exception as e:
            InfoBar.error(self.tr("程序错误"), self.tr("保存自定义大模型设置时发生内部错误: {0}").format(str(e)), parent=self)

    def check_for_updates(self, is_interactive: bool):
        """检查更新，is_interactive 为 True 表示用户点击按钮触发，False 为启动时自动检查"""
        current_version = VERSION
        # API URL，确保你的Flask服务器正在运行并且可以从客户端访问
        # 如果你的API在本地运行，并且客户端也是本地运行，通常是 http://localhost:port 或者 http://127.0.0.1:port
        # 如果API部署在其他地方，请使用相应的URL
        url = QUrl(f"{API_URL}/app/check-update?current_version={current_version}")
        request = QNetworkRequest(url)

        reply = self.network_manager.get(request)
        reply.finished.connect(lambda: self.handle_update_response(reply, is_interactive))

    def check_for_updates_interactive(self):
        self.check_for_updates(is_interactive=True)

    def check_for_updates_on_startup(self):
        if cfg.get(cfg.checkUpdateAtStartUp):
            self.check_for_updates(is_interactive=False)

    def handle_update_response(self, reply: QNetworkReply, is_interactive: bool):
        if reply.error() == QNetworkReply.NetworkError.NoError:
            try:
                response_data = json.loads(bytes(reply.readAll()).decode('utf-8'))
                status = response_data.get('status')
                if status == 'success':
                    update_available = response_data.get('update_available', False)
                    latest_version = response_data.get('latest_version', 'N/A')
                    download_url = response_data.get('download_url')
                    update_log = response_data.get('log', self.tr('无更新说明'))

                    if update_available:
                        title = self.tr("发现新版本")
                        content = self.tr("检测到 {1} 有新版本（{0}），是否立即前往下载？").format(latest_version, APP_NAME)
                        if update_log:
                            content += "\n" + self.tr("更新内容:") + "\n" + update_log
                        
                        # 使用 Fluent Design 的 Dialog
                        dialog = Dialog(title, content, self.window())
                        if dialog.exec():
                            if download_url:
                                self.open_download_url(download_url)
                            else:
                                InfoBar.warning(self.tr("未找到下载链接"), self.tr("新版本的下载链接缺失。"), parent=self)
                        
                    elif is_interactive:  # 仅在用户主动点击检查更新时提示已是最新
                        InfoBar.success(
                            self.tr("已是最新版本"),
                            self.tr("您正在使用最新版本 {0}（{1}）。").format(APP_NAME, latest_version),
                            duration=3000, 
                            parent=self
                        )
                else:
                    message = response_data.get('message', '服务器返回未知错误。')
                    if is_interactive:  # 仅在用户主动点击时显示错误详情
                        InfoBar.error(self.tr("检查更新失败"), message, parent=self)
                    print(f"检查更新失败（服务器逻辑）: {message}")
            except Exception as e: # Catches JSONDecodeError and other exceptions
                if is_interactive:
                    InfoBar.error(self.tr("检查更新失败"), self.tr("无法解析或处理更新响应。 ({0})").format(str(e)), parent=self)
                print(f"处理更新响应时出错: {e}")
        else:
            error_string = reply.errorString()
            if is_interactive:
                InfoBar.error(self.tr("网络错误"), self.tr("无法连接到更新服务器：{0}").format(error_string), parent=self)
            print(f"检查更新失败（网络）: {error_string}")
        reply.deleteLater()

    def open_download_url(self, url_string: str):
        """在默认浏览器中打开下载URL"""
        InfoBar.success(
            self.tr("正在打开下载链接"),
            self.tr("正在打开浏览器下载新版本"),
            duration=3000,
            parent=self.window()
        )
        QDesktopServices.openUrl(QUrl(url_string))
        # 打开链接后关闭主程序
        QTimer.singleShot(1000, QApplication.quit)
        